﻿using System;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;

namespace Red.Controls.Utils
{
    /// <summary>
    /// Manager for list views that expands last column so that it takes all space left in the list view
    /// </summary>
    public class ListViewManager
    {
        #region Data

        private readonly ListView _listView;
        private bool _resizing = false;

        #endregion Data

        #region Properties

        public static readonly DependencyProperty EnabledProperty = DependencyProperty.RegisterAttached(
            "Enabled",
            typeof( bool ),
            typeof( ListViewManager ),
            new FrameworkPropertyMetadata( OnEnabledChanged ) );

        public static void SetEnabled( DependencyObject dependencyObject, bool enabled )
        {
            dependencyObject.SetValue( EnabledProperty, enabled );
        }

        #endregion

        #region C-tor

        public ListViewManager( ListView listView )
        {
            _listView = listView;
            _listView.Loaded += ListView_Loaded;
            _listView.Unloaded += ListView_Unloaded;
            _listView.SizeChanged += ListView_SizeChanged;
            _listView.SetValue( ScrollViewer.HorizontalScrollBarVisibilityProperty, ScrollBarVisibility.Hidden );
        }

        #endregion

        #region Event handlers
        
        private static void OnEnabledChanged( DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e )
        {
            ListView listView = dependencyObject as ListView;
            if ( listView != null )
            {
                bool enabled = (bool)e.NewValue;
                if ( enabled )
                {
                    new ListViewManager( listView );
                }
            }
        }

        private void ListView_Loaded( object sender, RoutedEventArgs e )
        {
            ListView listView = sender as ListView;
            GridView gridView = listView.View as GridView;
            gridView.Columns.CollectionChanged += Columns_CollectionChanged;

            for ( int i = 0; i < gridView.Columns.Count; ++i )
            {
                GridViewColumn col = gridView.Columns[i];
                DependencyPropertyDescriptor.FromProperty( GridViewColumn.WidthProperty, typeof( GridViewColumn ) ).AddValueChanged( col, GridColumnWidthChanged );
            }
        }

        private void ListView_Unloaded( object sender, RoutedEventArgs e )
        {
            ListView listView = sender as ListView;
            GridView gridView = listView.View as GridView;
            gridView.Columns.CollectionChanged -= Columns_CollectionChanged;

            for ( int i = 0; i < gridView.Columns.Count; ++i )
            {
                GridViewColumn col = gridView.Columns[i];
                DependencyPropertyDescriptor.FromProperty( GridViewColumn.WidthProperty, typeof( GridViewColumn ) ).RemoveValueChanged( col, GridColumnWidthChanged );
            }
        }

        private void Columns_CollectionChanged( object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e )
        {
            if ( e.NewItems != null )
            {
                for ( int i = 0; i < e.NewItems.Count; ++i )
                {
                    GridViewColumn col = e.NewItems[i] as GridViewColumn;
                    DependencyPropertyDescriptor.FromProperty( GridViewColumn.WidthProperty, typeof( GridViewColumn ) ).AddValueChanged( col, GridColumnWidthChanged );
                }
            }
        }

        private void ListView_SizeChanged( object sender, SizeChangedEventArgs e )
        {
            ResizeColumns();
        }

        private void GridColumnWidthChanged( object sender, EventArgs e )
        {
            if ( !_resizing )
            {
                ResizeColumns();
            }
        }

        #endregion Event handlers

        #region Private methods

        private void ResizeColumns()
        {
            GridView gridView = _listView.View as GridView;
            if ( gridView.Columns.Count == 0 )
            {
                return;
            }

            _resizing = true;

            double columnsWidth = 0;
            for ( int i = 0; i < gridView.Columns.Count - 1; ++i )
            {
                columnsWidth += gridView.Columns[i].ActualWidth;
            }

            double actualWidth = _listView.ActualWidth;
            if ( double.IsInfinity( actualWidth ) || actualWidth <= 0 )
            {
                return;
            }

            double fillWidth = actualWidth - columnsWidth;
            if ( fillWidth > 50 )
            {
                gridView.Columns.Last().Width = fillWidth;
                _listView.SetValue( ScrollViewer.HorizontalScrollBarVisibilityProperty, ScrollBarVisibility.Hidden );
            }
            else
            {
                _listView.SetValue( ScrollViewer.HorizontalScrollBarVisibilityProperty, ScrollBarVisibility.Visible );
            }

            _resizing = false;
        }

        #endregion Private methods
    }
}
